#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <dlfcn.h>
#include <syslog.h>
#include<gio/gio.h>
#include<assert.h>
#include<fcntl.h>
#include<libusb.h>


#include "common.h"
#include "ofprint_common.h"
#include "usb_device.h"
#include "ofprint-server.h"

ofp_dev *dev_ofprint = NULL;

static const struct usb_id ofp1234_id_table[] = {
	{ .idVendor = 0x1234, .idProduct = 0xABCD, .description = "OMS OFP1234"},
	{ .idVendor = 0x33A7, .idProduct = 0x2303, .description = "OMS OFP2303"},
	{ .idVendor = 0x33A7, .idProduct = 0x2388, .description = "OMS OFP2388"},
	{ .idVendor = 0x33A7, .idProduct = 0x2882, .description = "OMS OFP2882"},

	{ 0, 0, NULL },
};

/* 定义全局变量 */
static int ofp_ops_timeout_ms = OFP_OPS_DEFAULT_TIMEOUT * 1000;	/** 操作的超时时间，单位：毫秒 **/


/* 全局配置文件 */
//GKeyFile * ofplist_conf = NULL;

int ofp_onekey_powerup_identify(ofp_dev *dev);
int ofp_conf_open(GKeyFile **ofplist_conf);
void ofp_conf_free(GKeyFile **ofplist_conf);



int ofp_conf_init()
{
	GKeyFile *ofplist_conf = NULL;
	//GError *err = NULL;

    DBG("ofp_conf_init ===================>enter\n");
	char cmd[1024] = {0};
	snprintf(cmd, 1024, "touch %s", OFP_FPRINT_LIST_FILE);
	WD_DBG("%s\n", cmd);
	if(0 > system(cmd))
        WD_ERR("exec failed!\n");

	if(0 != ofp_conf_open(&ofplist_conf))
	{
		WD_ERR("ofp_conf_open failed!!!\n");
		return -1;
	}



	ofp_conf_free(&ofplist_conf);
    DBG("ofp_conf_init <===================exit\n");

	return 0;
}

int ofp_conf_open(GKeyFile **ofplist_conf)
{
	*ofplist_conf = g_key_file_new();
	GError *err = NULL;

	g_key_file_load_from_file(*ofplist_conf, OFP_FPRINT_LIST_FILE, G_KEY_FILE_KEEP_TRANSLATIONS|G_KEY_FILE_KEEP_COMMENTS, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		g_key_file_free(*ofplist_conf);
		return -1;
	}

	return 0;
}

void ofp_conf_free(GKeyFile **ofplist_conf)
{
	if(NULL != *ofplist_conf)
	{
		g_key_file_free(*ofplist_conf);
		*ofplist_conf = NULL;
	}
}

#if 0
GKeyFile * ofp_bio_conf()
{
	return ofplist_conf;
}
#endif

int ofp_get_fprint_list(ofp_dev *dev)
{
	driver_info *priv = (driver_info *)dev->dev_priv;
	fprint_info *fprint_list = priv->fprint_list;
	GKeyFile * ofplist = NULL;
	GError *err = NULL;

    DBG("ofp_get_fprint_list =================>enter \n");
	WD_DBG("start.\n");

	if(0 != ofp_conf_open(&ofplist))
	{
		WD_ERR("open ofplist_conf failed!!!\n");
        DBG("ofp_conf_open failed \n");
		return -1;
	}
#if 0
	if (dev->enable == FALSE) {       // 设备不可用
		WD_ERR("device not enable!!!\n");
		ofp_conf_free(ofplist);
		return -1;
	}
#endif
	if(NULL == ofplist)
	{
		WD_ERR("ofplist_conf is NULL!!!\n");
		//ofp_conf_free(&ofplist);

        DBG("ofplist_conf is NULL!   failed \n");
		return -1;
	}

	if(0 >= dev->dev_num)
	{
		WD_ERR("device not online!!!\n");
        DBG("dev->dev_num = %d \n", dev->dev_num);
		ofp_conf_free(&ofplist);
		return -1;
	}
    //DBG("dev->dev_num = %d \n", dev->dev_num);

	for(int i = 0; i < OFP_FPRINT_NUM_MAX; i++)
	{
		char group[OFP_GROUP_NAME_MAX] = {0};
		bool enable = false;
		char *user_id = NULL;
		char *fprint_name = NULL;
		uint16 fprint_id = 0xffff;

		snprintf(group, OFP_GROUP_NAME_MAX, "UserFprint-%d", i+1);

		enable = g_key_file_get_boolean(ofplist, group, OFP_FPRINT_ENABLE, &err);
		if (err != NULL) {
			//WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
			g_error_free(err);
			err = NULL;
			continue;
		}

		fprint_list[i].enable = enable;

		if(true != enable)
		{
			continue;
		}
		//WD_DBG("enable = %d.\n", enable);

		user_id = g_key_file_get_string(ofplist, group, OFP_FPRINT_USER_ID, &err);
		if (err != NULL) {
			WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
			g_error_free(err);
			err = NULL;
			continue;
		}
		strcpy(fprint_list[i].user_id, user_id);
		WD_DBG("user_id = %s.\n", fprint_list[i].user_id);


		fprint_name = g_key_file_get_string(ofplist, group, OFP_FPRINT_NAME, &err);
		if (err != NULL) {
			WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
			g_error_free(err);
			err = NULL;
			continue;
		}
		strcpy(fprint_list[i].fprint_name, fprint_name);
		WD_DBG("fprint_name = %s.\n", fprint_list[i].fprint_name);

		fprint_id = g_key_file_get_integer(ofplist, group, OFP_FPRINT_ID, &err);
		if (err != NULL) {
			WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
			g_error_free(err);
			err = NULL;
			continue;
		}
		fprint_list[i].fprint_id = fprint_id;
		WD_DBG("fprint_id = %d.\n", fprint_list[i].fprint_id);

	}

	ofp_conf_free(&ofplist);
	WD_DBG("end.\n");
    DBG("ofp_get_fprint_list <=================exit \n");

	return 0;
}

int ofp_find_fprint_info(ofp_dev *dev, char *user_id, char *fprint_name, fprint_info **fprint_found)
{
	driver_info *priv = (driver_info *)dev->dev_priv;
	fprint_info *fprint_list = priv->fprint_list;
	int index = 0;

	if((NULL == dev)||(NULL == user_id)||(NULL == fprint_name)||(NULL == fprint_found))
	{
		WD_ERR(_("the param is error!!!\n"));
		return index;
	}

	WD_DBG("start.\n");

	for(int i = 0; i < OFP_FPRINT_NUM_MAX; i++)
	{
		if((true == fprint_list[i].enable)\
			&& (0 == strcmp(user_id, fprint_list[i].user_id))\
			&& (0 == strcmp(fprint_name, fprint_list[i].fprint_name)))
		{
			*fprint_found = &(fprint_list[i]);
			index = i+1;
			break;
		}
	}

	WD_DBG("index = %d.\n", index);

	return index;
}

int ofp_find_fprint_info_byfprintid(ofp_dev *dev, uint16 fprintid, fprint_info **fprint_found)
{
	driver_info *priv = (driver_info *)dev->dev_priv;
	fprint_info *fprint_list = priv->fprint_list;
	int index = 0;

	WD_DBG("start.\n");

	for(int i = 0; i < OFP_FPRINT_NUM_MAX; i++)
	{
		if((true == fprint_list[i].enable)\
			&& (fprintid == fprint_list[i].fprint_id))
		{
			*fprint_found = &(fprint_list[i]);
			index = i+1;
			break;
		}
	}

	WD_DBG("index = %d.\n", index);

	return index;
}


int ofp_get_empty_fprint_info(ofp_dev *dev)
{
	driver_info *priv = (driver_info *)dev->dev_priv;
	fprint_info *fprint_list = priv->fprint_list;
	int index = 0;

	for(int i = 0; i < OFP_FPRINT_NUM_MAX; i++)
	{
		if(false == fprint_list[i].enable)
		{
			index = i + 1;
			break;
		}
	}

	return index;
}

int ofp_set_fprint_info(ofp_dev *dev, int index, fprint_info *xfprint_info)
{
	driver_info *priv = (driver_info *)dev->dev_priv;
	fprint_info *fprint_list = priv->fprint_list;
	GKeyFile * ofplist = NULL;
	GError *err = NULL;
	char group[OFP_GROUP_NAME_MAX] = {0};

	if((NULL == dev) || (NULL == xfprint_info)\
		||(0 >= index) || (OFP_FPRINT_NUM_MAX < index))
	{
		WD_ERR("the param is error!!!\n");
		return -1;
	}

	if(0 != ofp_conf_open(&ofplist))
	{
		WD_ERR("open ofplist_conf failed!!!\n");
		return -1;
	}

	snprintf(group, OFP_GROUP_NAME_MAX, "UserFprint-%d", index);

	WD_DBG("[%s] enable=%d user_id=%s fprint_name=%s fprint_id=%d\n", \
		group, xfprint_info->enable, xfprint_info->user_id, xfprint_info->fprint_name, xfprint_info->fprint_id);

	WD_DBG("\n");
	gsize length;
	g_key_file_to_data(ofplist, &length, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		ofp_conf_free(&ofplist);
		return -1;
	}

	WD_DBG("\n");
	g_key_file_set_boolean(ofplist, group, OFP_FPRINT_ENABLE, xfprint_info->enable);
	g_key_file_set_string(ofplist, group, OFP_FPRINT_USER_ID, xfprint_info->user_id);
	g_key_file_set_string(ofplist, group, OFP_FPRINT_NAME, xfprint_info->fprint_name);
	g_key_file_set_integer(ofplist, group, OFP_FPRINT_ID, xfprint_info->fprint_id);

	WD_DBG("\n");
	g_key_file_save_to_file(ofplist, OFP_FPRINT_LIST_FILE, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		ofp_conf_free(&ofplist);
		return -1;
	}

	WD_DBG("\n");
	fprint_list[index-1].enable = xfprint_info->enable;
	strcpy(fprint_list[index-1].user_id, xfprint_info->user_id);
	strcpy(fprint_list[index-1].fprint_name, xfprint_info->fprint_name);
	fprint_list[index-1].fprint_id = xfprint_info->fprint_id;
	WD_DBG("\n");

	ofp_conf_free(&ofplist);

	return 0;
}


int ofp_add_fprint_info(ofp_dev *dev, fprint_info *xfprint_info)
{
	driver_info *priv = (driver_info *)dev->dev_priv;
	fprint_info *fprint_list = priv->fprint_list;
	fprint_info *fprint_found = NULL;
	int index = 0;

	WD_DBG("start.\n");

	ofp_find_fprint_info(dev, xfprint_info->user_id, xfprint_info->fprint_name, &fprint_found);

	if(NULL != fprint_found)
	{
		WD_ERR("fprint_info user_id=%s, fprint_name=%s already existed!!!\n", \
			xfprint_info->user_id, xfprint_info->fprint_name);
		return -1;
	}

	index = ofp_get_empty_fprint_info(dev);

	if(0 >= index)
	{
		WD_ERR("ofp_get_empty_fprint_info failed!!!\n");
		return -1;
	}

	if(0 != ofp_set_fprint_info(dev, index, xfprint_info))
	{
		WD_ERR("ofp_set_fprint_info failed!!!\n");
		return -1;
	}

	WD_DBG("end.\n");

	return 0;
}

int ofp_del_fprint_info(ofp_dev *dev, char *user_id, char *fprint_name)
{
	driver_info *priv = (driver_info *)dev->dev_priv;
	fprint_info *fprint_list = priv->fprint_list;
	fprint_info *fprint_found = NULL;
	int index = 0;

	index = ofp_find_fprint_info(dev, user_id, fprint_name, &fprint_found);

	if(NULL == fprint_found)
	{
		return 0;
	}

	if(true == fprint_found->enable)
	{
		fprint_found->enable = false;
		ofp_set_fprint_info(dev, index, fprint_found);
	}

	return 0;
}


int32 driver_config_init(DRIVER_CONFIG_STRUCT *config)
{
	GKeyFile *file = NULL;
	GError *err = NULL;
	int auto_suspend = 0;
	char *str_upgrade_mode = NULL;
	int printf_log_flag = 0;
	int upgrade_flag = 0;

	WD_DBG("start.\n");

	file = g_key_file_new();

	g_key_file_load_from_file(file, OFP_DRIVER_CONFIG_FILE, G_KEY_FILE_KEEP_TRANSLATIONS|G_KEY_FILE_KEEP_COMMENTS, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		g_key_file_free(file);
		return -1;
	}

	printf_log_flag = g_key_file_get_integer(file, BASIC_PARAM, PRINTF_LOG_FLAG, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		printf_log_flag = 0;
	}
	if(0 != printf_log_flag)
	{
		set_printf_log_grade(printf_log_flag);
		WD_LOG("================enable printf log================\n");
		WD_LOG("%s = %d.\n", PRINTF_LOG_FLAG, printf_log_flag);
	}

	auto_suspend = g_key_file_get_integer(file, BASIC_PARAM, AUTO_SUSPEND, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		auto_suspend = 0;
	}
	WD_DBG("set auto_suspend: %d\n", auto_suspend);
	config->autosuspend_flag = auto_suspend;
	usb_set_autosuspend_flag(config->autosuspend_flag);

	upgrade_flag = g_key_file_get_integer(file, BASIC_PARAM, STR_UPGRADE_FLAG, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		upgrade_flag = 0;
	}
	WD_DBG("set upgrade_flag: %d\n", upgrade_flag);
	config->upgrade_flag = upgrade_flag;

	str_upgrade_mode = g_key_file_get_string(file, BASIC_PARAM, UPGRADE_MODE, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		str_upgrade_mode = NULL;
	}

	if(NULL == str_upgrade_mode)
	{
		WD_DBG("set upgrade mode: %s\n", STR_AUTO_UPGRADE);
		config->upgrade_mode = AUTO_UPGRADE;
	}
	else if(0 == strcmp(STR_FORCE_UPGRADE, str_upgrade_mode))
	{
		WD_DBG("set upgrade mode: %s\n", STR_FORCE_UPGRADE);
		config->upgrade_mode = FORCE_UPGRADE;
	}
	else if(0 == strcmp(STR_DONT_UPGRADE, str_upgrade_mode))
	{
		WD_DBG("set upgrade mode: %s\n", STR_DONT_UPGRADE);
		config->upgrade_mode = DONT_UPGRADE;
	}
	else if(0 == strcmp(STR_AUTO_UPGRADE, str_upgrade_mode))
	{
		WD_DBG("set upgrade mode: %s\n", STR_AUTO_UPGRADE);
		config->upgrade_mode = AUTO_UPGRADE;
	}
	else if(0 == strcmp(STR_SMART_UPGRADE, str_upgrade_mode))
	{
		WD_DBG("set upgrade mode: %s\n", STR_SMART_UPGRADE);
		config->upgrade_mode = SMART_UPGRADE;
	}

	if(NULL != str_upgrade_mode)
	{
		g_free(str_upgrade_mode);
	}

	g_key_file_free(file);
	WD_DBG("end.\n");

	return 0;
}

int read_fw_upgrade_flag(void)
{
	GKeyFile *file = NULL;
	GError *err = NULL;
	int upgrade_flag = 0;
	int ret = -1;

	WD_DBG("start.\n");

	file = g_key_file_new();

	g_key_file_load_from_file(file, OFP_DRIVER_CONFIG_FILE, G_KEY_FILE_KEEP_TRANSLATIONS|G_KEY_FILE_KEEP_COMMENTS, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		g_key_file_free(file);
		return -1;
	}

	upgrade_flag = g_key_file_get_integer(file, BASIC_PARAM, STR_UPGRADE_FLAG, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		upgrade_flag = 0;
	}
	WD_DBG("upgrade_flag = %d\n", upgrade_flag);

	if(0 >= upgrade_flag)
	{
		ret = -1;
	}
	else
	{
		ret = 0;
	}

end:
	g_key_file_free(file);
	WD_DBG("end.\n");
	return ret;
}

int change_fw_upgrade_flag(void)
{
	GKeyFile *file = NULL;
	GError *err = NULL;
	int upgrade_flag = 0;
	int ret = -1;
	static uint8 upgrade_times = 0;

	WD_DBG("start.\n");

	if(0 < upgrade_times)
	{
		WD_DBG("upgrade_flag has been changed.\n");
		return 0;
	}

	file = g_key_file_new();

	g_key_file_load_from_file(file, OFP_DRIVER_CONFIG_FILE, G_KEY_FILE_KEEP_TRANSLATIONS|G_KEY_FILE_KEEP_COMMENTS, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		g_key_file_free(file);
		return -1;
	}

	upgrade_flag = g_key_file_get_integer(file, BASIC_PARAM, STR_UPGRADE_FLAG, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		upgrade_flag = 0;
		goto end;
	}
	WD_DBG("upgrade_flag = %d\n", upgrade_flag);
	if(0 >= upgrade_flag)
	{
		ret = 0;
		goto end;
	}

	upgrade_flag--;

	gsize length;
	g_key_file_to_data(file, &length, &err);
	if (err != NULL) {
		WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		goto end;
	}
	else
	{
		g_key_file_set_integer(file, BASIC_PARAM, STR_UPGRADE_FLAG, upgrade_flag);
		g_key_file_save_to_file(file, OFP_DRIVER_CONFIG_FILE, &err);
		if (err != NULL) {
			WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
			g_error_free(err);
			err = NULL;
			goto end;
		}
	}

	ret = 0;
	upgrade_times++;
	WD_DBG("change upgrade_flag = %d\n", upgrade_flag);

end:
	g_key_file_free(file);
	WD_DBG("end.\n");
	return ret;
}


#if 0
int ofp_dev_is_enable(bio_dev * dev, GKeyFile * conf)
{

	GError * err = NULL;
	if (dev->device_name == NULL)
		return FALSE;

	gboolean enable = g_key_file_get_boolean(conf, dev->device_name,
											   "Enable", &err);
	if (err != NULL) {
		bio_print_error(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
	} else bio_print_debug("IsEnable = %s\n", (enable)?"true":"false");
	return enable;
}
#endif

int bio_init(void) {
	int ret = 0;
#if 0
	setlocale (LC_ALL, "");
	bindtextdomain(LIBBIOMETRIC_DOMAIN_NAME, LOCALEDIR);

	bio_print_debug(_("Biometric framework API version:\n"));
	bio_print_debug(_("         Driver API(DRV_API): %d.%d.%d\n"),
					BIO_DRV_API_VERSION_MAJOR,
					BIO_DRV_API_VERSION_MINOR,
					BIO_DRV_API_VERSION_FUNC);
	bio_print_debug(_("    Application API(APP_API): %d.%d.%d\n"),
					BIO_APP_API_VERSION_MAJOR,
					BIO_APP_API_VERSION_MINOR,
					BIO_APP_API_VERSION_FUNC);

	/* 初始化配置 */
	if (bio_conf_init() != 0) {
		bio_print_error(_("bio_conf_init failed\n"));
		return -1;
	}

	/* 检测并升级数据库 */
	sqlite3 *db = bio_sto_connect_db();
	ret = bio_sto_check_and_upgrade_db_format(db);
	if (ret != 0 )
	{
		bio_sto_disconnect_db(db);
		return -1;
	}
#endif
	int rc;
	//rc = libusb_init (NULL);
	if (rc < 0)	{
		//bio_print_error(_("failed to initialise libusb: %s\n"), libusb_error_name(rc));
		return -1;
	}

	return 0;
}

int bio_close(void) {
	//libusb_exit (NULL);

	//bio_conf_free();

	return 0;
}

int ofp_ops_stop_ops(ofp_dev *dev, int waiting_sec){
	//return dev->ofp_stop_by_user(dev, waiting_sec * 1000);
	return 0;
}

void ofp_set_ops_timeout_ms(int t) {
	ofp_ops_timeout_ms = t;
}

int ofp_get_ops_timeout_ms() {
	return ofp_ops_timeout_ms;
}

bool ofp_is_stop_by_user(ofp_dev * dev) {
	if (dev->dev_status % 100 == DEVS_COMM_STOP_BY_USER)
		return true;
	else
		return false;
}

int ofp_get_dev_status(ofp_dev * dev) {
	return dev->dev_status;
}

void ofp_set_dev_status(ofp_dev * dev, int status) {
	dev->dev_status = status;

	ofp_status_changed_common_callback(dev->driver_id, STATUS_TYPE_DEVICE);
}

void ofp_set_dev_abs_status(ofp_dev * dev, int status) {
	dev->dev_status = status;

	ofp_status_changed_common_callback(dev->driver_id, STATUS_TYPE_DEVICE);
}

int ofp_get_ops_result(ofp_dev * dev) {
	return dev->ops_result;
}

void ofp_set_ops_result(ofp_dev * dev, int result) {
	int ops = 0;
	ops = ofp_get_dev_status(dev) / 100;
	result  = result % 100;
	dev->ops_result = ops * 100 + result;

	ofp_status_changed_common_callback(dev->driver_id, STATUS_TYPE_OPERATION);
}

void ofp_set_ops_abs_result(ofp_dev * dev, int result) {
	dev->ops_result = result;

	ofp_status_changed_common_callback(dev->driver_id, STATUS_TYPE_OPERATION);
}

int ofp_get_notify_mid(ofp_dev * dev) {
	return dev->notify_mid;
}

void ofp_set_notify_mid(ofp_dev * dev, int mid) {
	int ops = 0;
	ops = ofp_get_dev_status(dev) / 100;
	mid  = mid % 100;
	dev->notify_mid = ops * 100 + mid;

	ofp_status_changed_common_callback(dev->driver_id, STATUS_TYPE_NOTIFY);
}

void ofp_set_notify_abs_mid(ofp_dev * dev, int mid) {
	dev->notify_mid = mid;

    ofp_status_changed_common_callback(dev->driver_id, STATUS_TYPE_NOTIFY);
}

void ofp_set_all_status(ofp_dev * dev,
							int dev_status,
							int ops_result,
							int notify_mid)
{
	int type = ofp_get_dev_status(dev) / 100;
	dev->dev_status = type * 100 + (dev_status % 100);
	dev->ops_result = type * 100 + (ops_result % 100);
	dev->notify_mid = type * 100 + (notify_mid % 100);

	ofp_status_changed_common_callback(dev->driver_id, STATUS_TYPE_DEVICE);
	ofp_status_changed_common_callback(dev->driver_id, STATUS_TYPE_OPERATION);
	ofp_status_changed_common_callback(dev->driver_id, STATUS_TYPE_NOTIFY);
}

void ofp_set_all_abs_status(ofp_dev * dev,
							int dev_status,
							int ops_result,
							int notify_mid)
{
	dev->dev_status = dev_status;
	dev->ops_result = ops_result;
	dev->notify_mid = notify_mid;

	ofp_status_changed_common_callback(dev->driver_id, STATUS_TYPE_DEVICE);
	ofp_status_changed_common_callback(dev->driver_id, STATUS_TYPE_OPERATION);
	ofp_status_changed_common_callback(dev->driver_id, STATUS_TYPE_NOTIFY);
}

const char * ofp_get_dev_status_mesg(ofp_dev *dev){
	const char * mesg = NULL;

	//mesg = dev->ofp_get_dev_status_mesg(dev);
	if (mesg != NULL)
		return mesg;
	switch (ofp_get_dev_status(dev)) {
	case DEVS_COMM_IDLE:
		return _("Device idle");
	case DEVS_COMM_DOING:
		return _("Device is in process");
	case DEVS_COMM_STOP_BY_USER:
		return _("Terminating current operation");
	case DEVS_COMM_DISABLE:
		return _("Device is disabled");

	case DEVS_OPEN_DOING:
		return _("Opening device");
	case DEVS_OPEN_STOP_BY_USER:
		return _("Terminating open operation");

	case DEVS_ENROLL_DOING:
		return _("Enrolling");
	case DEVS_ENROLL_STOP_BY_USER:
		return _("Terminating enroll operation");

	case DEVS_VERIFY_DOING:
		return _("Verifying");
	case DEVS_VERIFY_STOP_BY_USER:
		return _("Terminating Verify operation");

	case DEVS_IDENTIFY_DOING:
		return _("Identifying");
	case DEVS_IDENTIFY_STOP_BY_USER:
		return _("Terminating identify operation");

	case DEVS_CAPTURE_DOING:
		return _("Capturing");
	case DEVS_CAPTURE_STOP_BY_USER:
		return _("Terminating capture operation");

	case DEVS_SEARCH_DOING:
		return _("Searching");
	case DEVS_SEARCH_STOP_BY_USER:
		return _("Terminating search operation");

	case DEVS_CLEAN_DOING:
		return _("Cleaning");
	case DEVS_CLEAN_STOP_BY_USER:
		return _("Terminating clean operation");

	case DEVS_GET_FLIST_DOING:
		return _("Getting feature list");
	case DEVS_GET_FLIST_STOP_BY_USER:
		return _("Terminating get feature list operation");

	case DEVS_RENAME_DOING:
		return _("Renaming feature");
	case DEVS_RENAME_STOP_BY_USER:
		return _("Terminating feature rename operation");

	case DEVS_CLOSE_DOING:
		return _("Closing");
	case DEVS_CLOSE_STOP_BY_USER:
		return _("Terminating close operation");

	default:
		//ofp_print_warning(_("Device unknown status code: %d\n"), ofp_get_dev_status(dev));
		return _("Device is in an unknown status...");
	}
}

const char * ofp_get_ops_result_mesg(ofp_dev *dev){
	const char * mesg = NULL;
	//mesg = dev->ops_get_ops_result_mesg(dev);
	if (mesg != NULL)
		return mesg;

	switch (ofp_get_ops_result(dev)) {
	case OPS_COMM_SUCCESS:
		return _("Operation successful");
	case OPS_COMM_FAIL:
		return _("Operation failed");
	case OPS_COMM_ERROR:
		return _("An error was encountered during the operation");
	case OPS_COMM_STOP_BY_USER:
		return _("The operation was interrupted by the user");
	case OPS_COMM_TIMEOUT:
		return _("Operation timeout");
	case OPS_COMM_OUT_OF_MEM:
		return _("Out of memory");

	case OPS_OPEN_SUCCESS:
		return _("Open device completion");
	case OPS_OPEN_FAIL:
		return _("Open device failed");
	case OPS_OPEN_ERROR:
		return _("An error was encountered during the opening");

	case OPS_ENROLL_SUCCESS:
		return _("Enroll feature successful");
	case OPS_ENROLL_FAIL:
		return _("Enroll feature failed");
	case OPS_ENROLL_ERROR:
		return _("An error was encountered during enrolling");
	case OPS_ENROLL_STOP_BY_USER:
		return _("Enroll operation was interrupted by the user");
	case OPS_ENROLL_TIMEOUT:
		return _("Enroll operation timeout");

	case OPS_VERIFY_MATCH:
		return _("Verify feature match");
	case OPS_VERIFY_NO_MATCH:
		return _("Verify feature no match");
	case OPS_VERIFY_ERROR:
		return _("An error was encountered during verifying");
	case OPS_VERIFY_STOP_BY_USER:
		return _("Verify operation was interrupted by the user");
	case OPS_VERIFY_TIMEOUT:
		return _("Verify operation timeout");

	case OPS_IDENTIFY_MATCH:
		return _("Identify feature match");
	case OPS_IDENTIFY_NO_MATCH:
		return _("Identify feature no match");
	case OPS_IDENTIFY_ERROR:
		return _("An error was encountered during identifying");
	case OPS_IDENTIFY_STOP_BY_USER:
		return _("Identify operation was interrupted by the user");
	case OPS_IDENTIFY_TIMEOUT:
		return _("Identify operation timeout");

	case OPS_CAPTURE_SUCCESS:
		return _("Capture feature successful");
	case OPS_CAPTURE_FAIL:
		return _("Capture feature failed");
	case OPS_CAPTURE_ERROR:
		return _("An error was encountered during capturing");
	case OPS_CAPTURE_STOP_BY_USER:
		return _("Capture operation was interrupted by the user");
	case OPS_CAPTURE_TIMEOUT:
		return _("Capture operation timeout");

	case OPS_SEARCH_MATCH:
		return _("Find the specified features");
	case OPS_SEARCH_NO_MATCH:
		return _("No specified features were found");
	case OPS_SEARCH_ERROR:
		return _("An error was encountered during searching");
	case OPS_SEARCH_STOP_BY_USER:
		return _("Search operation was interrupted by the user");
	case OPS_SEARCH_TIMEOUT:
		return _("Search operation timeout");

	case OPS_CLEAN_SUCCESS:
		return _("Clean feature successful");
	case OPS_CLEAN_FAIL:
		return _("Clean feature failed");
	case OPS_CLEAN_ERROR:
		return _("An error was encountered during cleaning");
	case OPS_CLEAN_STOP_BY_USER:
		return _("Clean operation was interrupted by the user");
	case OPS_CLEAN_TIMEOUT:
		return _("Clean operation timeout");

	case OPS_GET_FLIST_SUCCESS:
		return _("Get feature list completion");
	case OPS_GET_FLIST_FAIL:
		return _("Get feature list failed");
	case OPS_GET_FLIST_ERROR:
		return _("An error was encountered during getting feature list");

	case OPS_RENAME_SUCCESS:
		return _("Rename feature successful");
	case OPS_RENAME_FAIL:
		return _("Rename feature failed");
	case OPS_RENAME_ERROR:
		return _("An error was encountered during renaming");

	case OPS_CLOSE_SUCCESS:
		return _("Close device completion");
	case OPS_CLOSE_FAIL:
		return _("Close device failed");
	case OPS_CLOSE_ERROR:
		return _("An error was encountered during closing");

	default:
		return _("Operation is in an unknown status......");
	}
}

const char * ofp_get_notify_mid_mesg(ofp_dev *dev){
	const char * mesg = NULL;
	//mesg = dev->ops_get_notify_mid_mesg(dev);
	if (mesg != NULL)
		return mesg;

	switch (ofp_get_notify_mid(dev)) {
	case NOTIFY_COMM_IDLE:
		return _("Device idle");
	case NOTIFY_COMM_FAIL:
		return _("Operation failed");
	case NOTIFY_COMM_ERROR:
		return _("An error was encountered during the operation");
	case NOTIFY_COMM_STOP_BY_USER:
		return _("The operation was interrupted by the user");
	case NOTIFY_COMM_TIMEOUT:
		return _("Operation timeout");
	case NOTIFY_COMM_DISABLE:
		return _("Device is disable");
	case NOTIFY_COMM_OUT_OF_MEM:
		return _("Out of memory");
	case NOTIFY_COMM_UNSUPPORTED_OPS:
		return _("The device or driver does not support this operation");

	case NOTIFY_OPEN_SUCCESS:
		return _("Open device completion");
	case NOTIFY_OPEN_FAIL:
		return _("Open device failed");
	case NOTIFY_OPEN_ERROR:
		return _("An error was encountered during the opening");

	case NOTIFY_ENROLL_SUCCESS:
		return _("Enroll feature successful");
	case NOTIFY_ENROLL_FAIL:
		return _("Enroll feature failed");
	case NOTIFY_ENROLL_ERROR:
		return _("An error was encountered during enrolling");
	case NOTIFY_ENROLL_STOP_BY_USER:
		return _("Enroll operation was interrupted by the user");
	case NOTIFY_ENROLL_TIMEOUT:
		return _("Enroll operation timeout");

	case NOTIFY_VERIFY_MATCH:
		return _("Verify feature match");
	case NOTIFY_VERIFY_NO_MATCH:
		return _("Verify feature no match");
	case NOTIFY_VERIFY_ERROR:
		return _("An error was encountered during verifying");
	case NOTIFY_VERIFY_STOP_BY_USER:
		return _("Verify operation was interrupted by the user");
	case NOTIFY_VERIFY_TIMEOUT:
		return _("Verify operation timeout");

	case NOTIFY_IDENTIFY_MATCH:
		return _("Identify feature match");
	case NOTIFY_IDENTIFY_NO_MATCH:
		return _("Identify feature no match");
	case NOTIFY_IDENTIFY_ERROR:
		return _("An error was encountered during identifying");
	case NOTIFY_IDENTIFY_STOP_BY_USER:
		return _("Identify operation was interrupted by the user");
	case NOTIFY_IDENTIFY_TIMEOUT:
		return _("Identify operation timeout");

	case NOTIFY_CAPTURE_SUCCESS:
		return _("Capture feature successful");
	case NOTIFY_CAPTURE_FAIL:
		return _("Capture feature failed");
	case NOTIFY_CAPTURE_ERROR:
		return _("An error was encountered during capturing");
	case NOTIFY_CAPTURE_STOP_BY_USER:
		return _("Capture operation was interrupted by the user");
	case NOTIFY_CAPTURE_TIMEOUT:
		return _("Capture operation timeout");

	case NOTIFY_SEARCH_MATCH:
		return _("Find the specified features");
	case NOTIFY_SEARCH_NO_MATCH:
		return _("No specified features were found");
	case NOTIFY_SEARCH_ERROR:
		return _("An error was encountered during searching");
	case NOTIFY_SEARCH_STOP_BY_USER:
		return _("Search operation was interrupted by the user");
	case NOTIFY_SEARCH_TIMEOUT:
		return _("Search operation timeout");

	case NOTIFY_CLEAN_SUCCESS:
		return _("Clean feature successful");
	case NOTIFY_CLEAN_FAIL:
		return _("Clean feature failed");
	case NOTIFY_CLEAN_ERROR:
		return _("An error was encountered during cleaning");
	case NOTIFY_CLEAN_STOP_BY_USER:
		return _("Clean operation was interrupted by the user");
	case NOTIFY_CLEAN_TIMEOUT:
		return _("Clean operation timeout");

	case NOTIFY_GET_FLIST_SUCCESS:
		return _("Get feature list completion");
	case NOTIFY_GET_FLIST_FAIL:
		return _("Get feature list failed");
	case NOTIFY_GET_FLIST_ERROR:
		return _("An error was encountered during getting feature list");

	case NOTIFY_RENAME_SUCCESS:
		return _("Rename feature successful");
	case NOTIFY_RENAME_FAIL:
		return _("Rename feature failed");
	case NOTIFY_RENAME_ERROR:
		return _("An error was encountered during renaming");
	case NOTIFY_RENAME_INCOMPLETE:
		return _("Feature renaming is not complete, please try again");

	case NOTIFY_CLOSE_SUCCESS:
		return _("Close device completion");
	case NOTIFY_CLOSE_FAIL:
		return _("Close device failed");
	case NOTIFY_CLOSE_ERROR:
		return _("An error was encountered during closing");

	default:
		return _("Device internal error");
	}
}

/*
 * 检测usb设备，返回检测到的数量
 */
int ofp_common_detect_usb_device(ofp_dev *dev)
{
	int num = 0;

	return num;
}

/********** 内部函数实现 **********/
/* 分配一个ofp_dev资源 */
ofp_dev * ofp_dev_new()
{
	ofp_dev * dev;
	dev = malloc(sizeof(ofp_dev));
	if (dev != NULL)
		memset(dev, 0, sizeof(ofp_dev));
	return dev;
}

/* 释放bio_dev资源 */
void ofp_dev_free(ofp_dev * dev)
{
	dev->ops_free(dev);

	free(dev);
}

/* 状态变更的回调函数 */
void ofp_status_changed_common_callback(int drvid, int type)
{

}

/* 给上层服务提供的USB热插拔事件的回调函数接口 */
void ofp_usb_device_hot_plug_common_callbak(int drvid, int action, int dev_num_now)
{

}

void ofp_ops_free(ofp_dev *dev)
{
	if(NULL != dev->dev_priv)
	{
		g_free(dev->dev_priv);
	}
}

int ofp_ops_discover(ofp_dev *dev)
{
	int dev_num = 0;
    DBG("=====================> ofp_ops_discover enter \n");
	if(NULL != usb_get_dev_handle())
	{
		dev_num = 1;

	}
	else if(DRV_OK == usb_dev_open(dev))
	{
		usb_dev_close();
		dev_num = 1;
	}

	dev->dev_num = dev_num;
    DBG("ofp_ops_discover dev_num = %d \n", dev_num);
    DBG("<===================== ofp_ops_discover exit \n");

	return dev_num;
}

/* USB设备插入时的回调函数 */
static int ofp_usb_hotplug_callback_attach(libusb_context *ctx,
										   libusb_device *usbdev,
										   libusb_hotplug_event event,
										   void *user_data)
{
	struct libusb_device_descriptor desc;
	int rc;

	WD_DBG("start *************\r\n");

	rc = libusb_get_device_descriptor(usbdev, &desc);
	if (LIBUSB_SUCCESS != rc) {
		WD_ERR(_("Error: Can not get device descriptor\n"));
	}

	WD_LOG(_("Device attached: %04x:%04x\n"), desc.idVendor, desc.idProduct);

	ofp_dev * dev = dev_ofprint;
	driver_info *priv = (driver_info *)dev->dev_priv;

	if (dev->enable == 0)
	{
		return 0;
	}

	int i;
	const struct usb_id *id_table = dev->usb_info.id_table;

	for (i = 0; id_table[i].idVendor != 0; i++)
	{
		if (id_table[i].idVendor == desc.idVendor &&
				id_table[i].idProduct == desc.idProduct)
		{
			dev->ops_discover(dev);
			break;
		}
	}

	if(dev->dev_num > 0)
	{
		priv->dev_state |= DeviceStateNormal;
		priv->set_dev_state(priv->dev_state);
	}

	if(DEVS_COMM_IDLE != ofp_get_dev_status(dev))
	{
		usb_dev_open(dev);//当识别到错误指纹时，usb会断开，此处规避，add by hcq, 20230323
	}

	usb_dev_get_port_path();
	usb_dev_enable_autosuspend();

	WD_DBG("end *************\r\n");

	return 0;
}

/* USB设备拔出时的回调函数 */
static int ofp_usb_hotplug_callback_detach(libusb_context *ctx,
										   libusb_device *usbdev,
										   libusb_hotplug_event event,
										   void *user_data)
{
	struct libusb_device_descriptor desc;
	int rc;

	WD_DBG("start *************\r\n");
	usb_dev_set_port_path_valid_flag(0);

	rc = libusb_get_device_descriptor(usbdev, &desc);
	if (LIBUSB_SUCCESS != rc) {
		WD_DBG(_("Error getting device descriptor"));
	}

	WD_LOG(_("Device detached: %04x:%04x\n"), desc.idVendor, desc.idProduct);

	ofp_dev * dev = dev_ofprint;
	driver_info *priv = (driver_info *)dev->dev_priv;

	if (dev->enable == 0)
	{
		return 0;
	}

	int i;
	const struct usb_id *id_table = dev->usb_info.id_table;

	for (i = 0; id_table[i].idVendor != 0; i++)
	{
		if (id_table[i].idVendor == desc.idVendor &&
				id_table[i].idProduct == desc.idProduct)
		{
			dev->ops_discover(dev);
			break;
		}
	}

	if (dev->dev_num <= 0)
	{
		priv->dev_state &=~ DeviceStateNormal;
		//priv->set_dev_state(priv->dev_state);//设备拔出时不再设置状态为设备不可用, by hcq, 20231102
	}

	usb_dev_set_null();	//当识别到错误指纹时，usb会断开，此处规避，add by hcq, 20230323
	WD_DBG("end *************\r\n");

	return 0;
}

void monitor_usb_hotplug(void* para)
{
	int rc =0;

	while (1)
	{
		rc = libusb_handle_events (NULL);
		if (rc < 0)
			WD_ERR(_("libusb_handle_events failed: %s\n"), libusb_error_name(rc));
	}
}


int ofp_drv_init(ofp_dev *dev)
{
	GKeyFile * conf = NULL;
	gchar **  drv_list_conf = NULL;
	gsize driver_count = 0;
	ofp_dev * p = dev;

	/* 检测驱动版本*/
	WD_LOG(_("%s driver DRV_API version: %d.%d.%d\n"),
					p->device_name,
					p->drv_api_version.major,
					p->drv_api_version.minor,
					p->drv_api_version.function);

	/* 注册USB热插拔时的回掉函数 */
	int rc = 0;
	int i;
	const struct usb_id * id_table = p->usb_info.id_table;
	if(!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG))
	{
		WD_LOG("this libusb doesn't support hotplug.")
		dev->ops_discover(dev);
		return 0;
	}

	for (i = 0; id_table[i].idVendor != 0; i++)
	{
		WD_DBG("i = %d, idVendor = 0x%x, idProduct = 0x%x\n", \
			i, id_table[i].idVendor, id_table[i].idProduct);
		rc = libusb_hotplug_register_callback(NULL,
											  LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED,
											  0,
											  id_table[i].idVendor,
											  id_table[i].idProduct,
											  LIBUSB_HOTPLUG_MATCH_ANY,
											  ofp_usb_hotplug_callback_attach,
											  NULL,
											  &(p->usb_info.callback_handle)[0]);
		if (LIBUSB_SUCCESS != rc) {
			WD_ERR(_("Error: Can not register attach callback error\n"));
		}

		rc = libusb_hotplug_register_callback (NULL,
											   LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
											   0,
											   id_table[i].idVendor,
											   id_table[i].idProduct,
											   LIBUSB_HOTPLUG_MATCH_ANY,
											   ofp_usb_hotplug_callback_detach,
											   NULL,
											   &(p->usb_info.callback_handle)[1]);
		if (LIBUSB_SUCCESS != rc) {
			WD_ERR(_("Error: Can not register detach callback error\n"));
		}
	}

	int err = 0;
	pthread_t thr;

	err = pthread_create(&thr, NULL, (void *)monitor_usb_hotplug, NULL);
	if (err != 0) {
		WD_ERR(_("Can't create thread: %s\n"), strerror(err));
	}

	WD_DBG(_("end\n"));

	return 0;
}

int ofp_param_config(ofp_dev *dev)
{
	driver_info *priv = (driver_info *)dev->dev_priv;
	int mode_flag = 0;
	int reboot_flag = 0;
	bool enable = true;
	GKeyFile *ofplist = NULL;
	GError *err = NULL;
	int update_enable = 0;
	int printf_log_flag = 0;

	WD_DBG("start.\n");

	if(0 != ofp_conf_open(&ofplist))
	{
		WD_ERR("open ofplist_conf failed!!!\n");
		return -1;
	}

	enable = g_key_file_get_boolean(ofplist, OFP_DEVICE_PARAM, OFP_DEVICE_ENABLE, &err);
	if (err != NULL)
	{
		g_error_free(err);
		err = NULL;
		enable = true;
		update_enable = 1;
	}
	dev->enable = enable;
	WD_DBG("device enable = %d.\n", enable);

	printf_log_flag = g_key_file_get_integer(ofplist, OFP_DEVICE_PARAM, PRINTF_LOG_FLAG, &err);
	if (err != NULL) {
		//WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		printf_log_flag = 0;
	}
	if(0 != printf_log_flag)
	{
		set_printf_log_grade(printf_log_flag);
		WD_LOG("%s = %d.\n", PRINTF_LOG_FLAG, printf_log_flag);
	}


	mode_flag = g_key_file_get_integer(ofplist, OFP_DEVICE_PARAM, OFP_MODE_FLAG, &err);
	if (err != NULL) {
		//WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		mode_flag = 0;
	}
	priv->mode_flag = mode_flag;
	WD_LOG("%s = %d.\n", OFP_MODE_FLAG, priv->mode_flag);

	reboot_flag = g_key_file_get_integer(ofplist, OFP_DEVICE_PARAM, OFP_REBOOT_FLAG, &err);
	if (err != NULL) {
		//WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
		g_error_free(err);
		err = NULL;
		reboot_flag = 0;
	}
	priv->reboot_flag = reboot_flag;
	WD_LOG("%s = %d.\n", OFP_REBOOT_FLAG, priv->reboot_flag);

	if((0 != update_enable)||(0 != mode_flag)||(0 != reboot_flag))
	{
		gsize length;
		g_key_file_to_data(ofplist, &length, &err);
		if (err != NULL) {
			WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
			g_error_free(err);
			err = NULL;
		}
		else
		{
			if(0 != update_enable)
				g_key_file_set_boolean(ofplist, OFP_DEVICE_PARAM, OFP_DEVICE_ENABLE, enable);

			if(0 != mode_flag)
				g_key_file_set_integer(ofplist, OFP_DEVICE_PARAM, OFP_MODE_FLAG, 0);

			if(0 != reboot_flag)
				g_key_file_set_integer(ofplist, OFP_DEVICE_PARAM, OFP_REBOOT_FLAG, 0);

			g_key_file_save_to_file(ofplist, OFP_FPRINT_LIST_FILE, &err);
			if (err != NULL) {
				WD_ERR(_("Error[%d]: %s\n"), err->code, err->message);
				g_error_free(err);
				err = NULL;
			}
		}
	}

	ofp_conf_free(&ofplist);
	WD_DBG("end.\n");

	return 0;
}



int ofp_dev_init()
{
	dev_ofprint = ofp_dev_new();
	ofp_dev *dev = dev_ofprint;
	dev->device_name = OFPRINT_DEVICE_NAME;
	dev->full_name = OFPRINT_DEVICE_FULL_NAME;
	dev->drv_api_version.major = DRIVER_VERSION_MAJOR;//驱动软件版本
	dev->drv_api_version.minor = DRIVER_VERSION_MINOR;
	dev->drv_api_version.function = DRIVER_VERSION_FUNCTION;
	dev->enable = true;
	dev->dev_num = 1;
	dev->usb_info.id_table = ofp1234_id_table;
	dev->max_user = 1;
	dev->max_sample = 50;
	dev->sample_times = 12;


    pthread_mutex_init(&(dev->mutex), NULL);  // 初始化锁

    pthread_mutex_init(&(dev->bulk_mutex), NULL);  // 初始化锁



	driver_info *priv = g_new0 (driver_info, 1);
	dev->dev_priv = priv;
	priv->timeoutMS = 30*1000;
	priv->dev_state = 0;
	priv->ctrlFlag = CONTROL_FLAG_IDLE;
	priv->mode_flag = 0;
	priv->reboot_flag = 0;
	memset(priv->fprint_list, 0x00, sizeof(priv->fprint_list));
	priv->set_dev_state = ofp_set_dev_state;

	dev->ops_free = ofp_ops_free;
	dev->ops_discover = ofp_ops_discover;

	ofp_set_dev_status(dev, DEVS_COMM_IDLE);
	ofp_set_ops_result(dev, OPS_COMM_SUCCESS);
	ofp_set_notify_mid(dev, NOTIFY_COMM_IDLE);

	driver_config_init(&(priv->config));
	ofp_param_config(dev);

	return 0;
}



